#!/usr/bin/env python
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from buildbot.process import buildrequest
from buildbot.process.properties import WithProperties
from buildbot.scheduler import Nightly
from buildbot.scheduler import Triggerable
from buildbot.schedulers.basic import SingleBranchScheduler

from master import gitiles_poller
from master import master_utils
from master import slaves_list
from master.factory import annotator_factory
from master.factory import remote_run_factory

import config
import master_site_config

import math

ActiveMaster = master_site_config.V8FYI
MAIL_NOTIFIER = ActiveMaster.is_production_host

INFRA_REPO_URL = 'https://chromium.googlesource.com/infra/infra'

# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {}
c['status'] = []


####### DATABASE

config.DatabaseSetup(c)


####### CHANGESOURCES

comparator = gitiles_poller.GitilesRevisionComparator()
c['change_source'] = [
  gitiles_poller.GitilesPoller(
      'https://chromium.googlesource.com/v8/v8',
      branches=['master'],
      pollInterval=20,
      comparator=comparator,
  )
]

# TODO(machenbach): Find common place for this and internal copy:
# http://shortn/_PM6ecAbllK
def merge_requests_logarithmic(req1, req2, queue_length, merged_length):
  """Merges builds dependent on the number of builds in the queue."""
  if not buildrequest.BuildRequest.canBeMergedWith(req1, req2):
    return False

  return merged_length <= int(math.log(queue_length, 2))

# Tell buildbot that we want to use a non-standard fuction with 4 parameters.
setattr(merge_requests_logarithmic, 'with_length', True)

####### FACTORIES

F = annotator_factory.AnnotatorFactory(ActiveMaster).BaseFactory

def m_remote_run(recipe, **kwargs):
  props = {'path_config': 'kitchen'}
  props.update(kwargs.pop('properties', {}))
  return remote_run_factory.RemoteRunFactory(
    active_master=ActiveMaster,
    repository=kwargs.pop(
        'repository',
        'https://chromium.googlesource.com/chromium/tools/build.git'
    ),
    recipe=recipe,
    factory_properties=props,
    **kwargs)

####### BUILDER SPECS

CATEGORY_RELEASE = '1Release|release'
CATEGORY_LAYOUT = '2Layout|chromium'
CATEGORY_NONLAYOUT = '3Nonlayout|chromium'
CATEGORY_NONLAYOUT_NO_MAIL = '3Nonlayout'
CATEGORY_GPU_NO_MAIL = '4GPU'
CATEGORY_CLUSTERFUZZ = '5Clusterfuzz'
CATEGORY_NODE_JS = '6Node.js|node'

nightly_builders = [
  {
    'name': 'V8 lkgr finder',
    'builddir': 'v8-lkgr',
    'factory': m_remote_run(
        'lkgr_finder',
        repository=INFRA_REPO_URL,
        properties={'lkgr_project': 'v8', 'allowed_lag': 4},
    ),
    'category': CATEGORY_RELEASE,
    'auto_reboot' : False,
  },
  {
    'name': 'Auto-roll - push',
    'builddir': 'auto-roll-push',
    'factory': F('v8/auto_roll_push'),
    'category': CATEGORY_RELEASE,
    'auto_reboot' : False,
  },
  {
    'name': 'Auto-roll - deps',
    'builddir': 'auto-roll-deps',
    'factory': F('v8/auto_roll_deps'),
    'category': CATEGORY_RELEASE,
    'auto_reboot' : False,
  },
  {
    'name': 'Auto-roll - v8 deps',
    'builddir': 'auto-roll-v8-deps',
    'factory': F('v8/auto_roll_v8_deps'),
    'category': CATEGORY_RELEASE,
    'auto_reboot' : False,
  },
  {
    'name': 'Auto-roll - v8rel',
    'builddir': 'v8rel',
    'factory': F('v8/auto_roll_v8rel'),
    'category': CATEGORY_RELEASE,
    'auto_reboot' : False,
  },
  {
    'name': 'Auto-roll - release process',
    'builddir': 'release',
    'factory': F('v8/auto_roll_release_process'),
    'category': CATEGORY_RELEASE + '|clusterfuzz',
    'auto_reboot' : False,
  },
  {
    'name': 'V8 - node.js baseline',
    'builddir': 'node_js_baseline',
    'factory': F('v8/node_integration'),
    'category': CATEGORY_NODE_JS,
    'auto_reboot' : True,
  },
]


scheduled_builders = [
  {
    'name': 'V8-Blink Win',
    'factory': m_remote_run('blink_downstream'),
    'category': CATEGORY_LAYOUT,
  },
  {
    'name': 'V8-Blink Mac',
    'factory': m_remote_run('blink_downstream'),
    'category': CATEGORY_LAYOUT,
  },
  {
    'name': 'V8-Blink Linux 64',
    'factory': m_remote_run('blink_downstream'),
    'category': CATEGORY_LAYOUT,
    # Build all revisions.
    'mergeRequests': False,
  },
  {
    'name': 'V8-Blink Linux 64 - ignition',
    'factory': m_remote_run('blink_downstream'),
    'category': CATEGORY_LAYOUT,
  },
  {
    'name': 'V8-Blink Linux 64 (dbg)',
    'factory': m_remote_run('blink_downstream'),
    'category': CATEGORY_LAYOUT,
    'mergeRequests': merge_requests_logarithmic,
  },
  {
    'name': 'Linux Debug Builder',
    'factory': m_remote_run(
        'chromium', triggers=['cr_linux_dbg']),
    'category': CATEGORY_NONLAYOUT,
  },
  {
    'name': 'V8 Linux GN',
    'factory': m_remote_run('chromium'),
    'category': CATEGORY_NONLAYOUT,
  },
  {
    'name': 'V8 Android GN (dbg)',
    'factory': m_remote_run('chromium'),
    'category': CATEGORY_NONLAYOUT,
  },
  {
    'name': 'Linux ASAN Builder',
    'factory': m_remote_run('chromium'),
    'category': CATEGORY_NONLAYOUT,
  },
  {
    'name': 'Android Builder',
    'factory': F('android/builder'),
    'category': CATEGORY_NONLAYOUT,
  },
  {
    'name': 'Linux Snapshot Builder',
    'factory': m_remote_run('chromium'),
    'category': CATEGORY_NONLAYOUT_NO_MAIL,
  },
  {
    'name': 'Win Release (NVIDIA)',
    'factory': m_remote_run('chromium'),
    'category': CATEGORY_GPU_NO_MAIL,
  },
  {
    'name': 'Mac Release (Intel)',
    'factory': m_remote_run('chromium'),
    'category': CATEGORY_GPU_NO_MAIL,
  },
  {
    'name': 'Linux Release (NVIDIA)',
    'factory': m_remote_run('chromium'),
    'category': CATEGORY_GPU_NO_MAIL,
  },
  {
    'name': 'Android Release (Nexus 5X)',
    'factory': m_remote_run('chromium'),
    'category': CATEGORY_GPU_NO_MAIL,
  },
  {
    'name': 'V8 Linux64 - release builder',
    'factory': F('v8'),
    'category': CATEGORY_CLUSTERFUZZ,
    'mergeRequests': False,
  },
  {
    'name': 'V8 Linux64 - debug builder',
    'factory': F('v8'),
    'category': CATEGORY_CLUSTERFUZZ,
    'mergeRequests': False,
  },
  {
    'name': 'V8 Linux64 ASAN no inline - release builder',
    'factory': F('v8'),
    'category': CATEGORY_CLUSTERFUZZ,
    'mergeRequests': False,
  },
  {
    'name': 'V8 Linux64 ASAN - debug builder',
    'factory': F('v8'),
    'category': CATEGORY_CLUSTERFUZZ,
    'mergeRequests': False,
  },
  {
    'name': 'V8 Linux64 ASAN arm64 - debug builder',
    'factory': F('v8'),
    'category': CATEGORY_CLUSTERFUZZ,
    'mergeRequests': False,
  },
  {
    'name': 'V8 Linux ASAN arm - debug builder',
    'factory': F('v8'),
    'category': CATEGORY_CLUSTERFUZZ,
    'mergeRequests': False,
  },
  {
    'name': 'V8 Linux ASAN mipsel - debug builder',
    'factory': F('v8'),
    'category': CATEGORY_CLUSTERFUZZ,
    'mergeRequests': False,
  },
]

node_js_builders = [
  {
    'name': 'V8 - node.js integration',
    'builddir': 'node_js',
    'factory': F('v8/node_integration'),
    'category': CATEGORY_NODE_JS,
    'auto_reboot' : True,
  },
]

triggered_builders = [
  {
    'name': 'Linux Tests (dbg)(1)',
    'factory': m_remote_run('chromium'),
    'category': CATEGORY_NONLAYOUT_NO_MAIL,
  },
]


####### SCHEDULERS

c['schedulers'] = [
  SingleBranchScheduler(
      name='v8_fyi',
      branch='master',
      treeStableTimer=10,
      builderNames=[
        builder['name']
        for builder in scheduled_builders + node_js_builders
      ],
  ),
  Triggerable('cr_linux_dbg', ['Linux Tests (dbg)(1)']),
  # LKGR finder.
  Nightly(
      name='v8_lkgr_finder',
      branch=None,
      builderNames=['V8 lkgr finder'],
      minute=range(8, 60, 15),
  ),
  # Auto-roll builders.
  Nightly(
      name='v8_release_process',
      branch=None,
      builderNames=['Auto-roll - release process'],
      minute=range(10, 60, 15),
  ),
  Nightly(
      name='v8_auto_push',
      branch=None,
      builderNames=['Auto-roll - push'],
      minute=range(12, 60, 15),
  ),
  Nightly(
      name='v8_v8rel',
      branch=None,
      builderNames=[
        'Auto-roll - v8rel',
        'Auto-roll - deps',
      ],
      minute=range(0, 60, 15),
  ),
  # Run v8 deps roller every EMEA morning at 5am.
  Nightly(
      name='v8_v8deps',
      branch=None,
      builderNames=['Auto-roll - v8 deps'],
      hour=[20],
  ),
  # Node.js baseline checker runs every 30 minutes.
  Nightly(
      name='v8_node_baseline',
      branch=None,
      builderNames=['V8 - node.js baseline'],
      minute=range(7, 60, 30),
  ),
]

####### BUILDERS

c['builders'] = (
    nightly_builders +
    scheduled_builders +
    triggered_builders +
    node_js_builders
)

# Associate the slaves to the builders. The configuration is in slaves.cfg.
slaves = slaves_list.SlavesList('slaves.cfg', 'V8FYI')
for builder in c['builders']:
  builder['slavenames'] = slaves.GetSlavesName(builder=builder['name'])


####### BUILDSLAVES

# The 'slaves' list defines the set of allowable buildslaves. List all the
# slaves registered to a builder. Remove dupes.
c['slaves'] = master_utils.AutoSetupSlaves(c['builders'],
                                           config.Master.GetBotPassword())

# Make sure everything works together.
master_utils.VerifySetup(c, slaves)


####### STATUS TARGETS

# Buildbot master url:
# Must come before AutoSetupMaster().
c['buildbotURL'] = ActiveMaster.buildbot_url

# Adds common status and tools to this master.
master_utils.AutoSetupMaster(c, ActiveMaster,
    public_html='../master.chromium/public_html',
    tagComparator=comparator,
    templates=['../master.client.v8/templates',
               '../master.chromium/templates'])

if MAIL_NOTIFIER:
  import mail_notifier_cfg
  mail_notifier_cfg.Update(config, ActiveMaster, c)

# Adjust the buildCaches to be 3x the number of slaves per builder.
c['autoBuildCacheRatio'] = 3


####### PROJECT IDENTITY

c['projectName'] = ActiveMaster.project_name
c['projectURL'] = config.Master.project_url
